<?php

class Db
{
    public $db;
    public $sqls = array();
    private static $instance = array();

    public function __construct($data)
    {
        $dsn = "mysql:dbname=" . $data['dbname'] . ";host=" . $data['dbhost'];
        try {
            $this->db = new PDO($dsn, $data['dbuser'], $data['dbpassword']);
            $this->db->query('set character set utf8mb4;');
            $this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
        } catch (PDOException $e) {
            var_dump($e->getMessage());
        }
    }

    public static function get($key = 'Main')
    {
        $database['dbname'] = Tool::ini($key . 'DbName');
        $database['dbuser'] = Tool::ini($key . 'DbUser');
        $database['dbpassword'] = Tool::ini($key . 'DbPassword');
        $database['dbhost'] = Tool::ini($key . 'DbHost');
        if (!isset(self::$instance[$database['dbname']]) || !self::$instance[$database['dbname']] instanceof self) {
            self::$instance[$database['dbname']] = new Db($database);
        }
        return self::$instance[$database['dbname']];
    }

    public function count($sql, $parameters = null)
    {
        $data = array();
        $data['sql'] = $sql;
        $data['param'] = $parameters;
        $this->sqls[] = json_encode($data);
        $this->sqls[] = $sql;
        try {
            $res = $this->exeupdate($sql, $parameters);
            return $res;
        } catch (Exception $e) {
            throw new Exception("false");
        }
    }

    public function querysql($sql, $parameters = null)
    {
        $data = array();
        $data['sql'] = $sql;
        $data['param'] = $parameters;
        $this->sqls[] = json_encode($data);
        $this->sqls[] = $sql;
        try {
            return $this->exeupdate($sql, $parameters);
        } catch (\PDOException $e) {
            echo $e->getMessage();
            throw new Exception("false");
        }
    }

    public function querysqlinsertid($sql, $parameters = null)
    {
        $data = array();
        $data['sql'] = $sql;
        $data['param'] = $parameters;
        $this->sqls[] = json_encode($data);
        $this->sqls[] = $sql;
        try {
            if ($this->exeupdate($sql, $parameters)) {
                return $this->db->lastInsertId();
            } else {
                return 0;
            }
        } catch (Exception $e) {
            throw new Exception("false");
        }
    }

    public function getRow($sql, $parameters = null)
    {
        $data = array();
        $data['sql'] = $sql;
        $data['param'] = $parameters;
        $this->sqls[] = json_encode($data);
        try {
            $res = $this->exequery($sql, $parameters);
            if (count($res) > 0) {
                return $res[0];
            } else {
                return array();
            }
        } catch (Exception $e) {
            echo $e->getMessage();
            throw new Exception("false");
        }
    }

    public function getAll($sql, $parameters = null)
    {
        $data = array();
        $data['sql'] = $sql;
        $data['param'] = $parameters;
        $this->sqls[] = json_encode($data);
        try {
            $res = $this->exequery($sql, $parameters);
            if (count($res) > 0) {
                return $res;
            } else {
                return array();
            }
        } catch (Exception $e) {
            echo $e->getMessage();
            throw new Exception("false");
        }
    }

    public function beginTransaction()
    {
        try {
            $this->db->beginTransaction();
        } catch (Exception $e) {
            echo $e->getMessage();
            throw new Exception("false");
        }
    }

    public function rollback()
    {
        try {
            $this->db->rollback();
        } catch (Exception $e) {
            echo $e->getMessage();
            throw new Exception("false");
        }
    }

    public function commit()
    {
        try {
            $this->db->commit();
        } catch (Exception $e) {
            echo $e->getMessage();
            throw new Exception("false");
        }
    }

    public function exequery($sql, $parameters = null)
    {
        $conn = $this->db;
        $stmt = $conn->prepare($sql);
        try {
            $stmt->execute($parameters);
        } catch (Exception $e) {
            throw new Exception("false");
        }

        $rs = $stmt->fetchall(PDO::FETCH_ASSOC);
        $stmt = null;
        $conn = null;
        return $rs;
    }

    public function exeupdate($sql, $parameters = null)
    {
        try {
            $stmt = $this->db->prepare($sql);
            $stmt->execute($parameters);
            $affectedrows = $stmt->rowcount();
            $stmt = null;
            $conn = null;
            return $affectedrows;
        } catch (Exception $e) {
            echo $e->getMessage();
            exit;
        }
    }

    public function checklink()
    {
        $res = $this->db->getAttribute(PDO::ATTR_SERVER_INFO);
        if (strpos($res, 'server has gone away') !== false) {
            $this->db = null;
            return false;
        } else {
            return true;
        }
    }

    public function getinsertid()
    {
        try {
            return $this->db->lastInsertId();
        } catch (Exception $e) {
            echo $e->getMessage();
        }
    }
}